package com.htsk.city.services.wechat.controller;

import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.IdUtil;
import cn.hutool.json.JSONUtil;
import com.alibaba.fastjson2.JSON;
import com.github.binarywang.wxpay.bean.notify.WxPayNotifyResponse;
import com.github.binarywang.wxpay.bean.notify.WxPayOrderNotifyResult;
import com.github.binarywang.wxpay.bean.order.WxPayMpOrderResult;
import com.github.binarywang.wxpay.bean.request.WxPayUnifiedOrderRequest;
import com.github.binarywang.wxpay.bean.result.enums.TradeTypeEnum;
import com.github.binarywang.wxpay.exception.WxPayException;
import com.github.binarywang.wxpay.service.WxPayService;
import com.htsk.city.services.core.dao.OrderItemDao;
import com.htsk.city.services.core.dao.OrderMasterDao;
import com.htsk.city.services.core.dao.OrderOperationLogDao;
import com.htsk.city.services.core.domain.OrderMaster;
import com.htsk.city.services.core.domain.OrderOperationLog;
import com.htsk.city.services.core.domain.WxUser;
import com.htsk.city.services.core.entity.R;
import com.htsk.city.services.core.enums.OrderStatus;
import com.htsk.city.services.core.utils.IpUtils;
import com.htsk.city.services.wechat.annotation.GetUserInfo;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.math.BigDecimal;
import java.time.Instant;
import java.util.Date;
import java.util.Optional;

/**
 * @Author 李树洪
 * @Email 2324592742@qq.com
 * @Date 2025/9/23 14:17
 */
@RestController
@RequestMapping("/wxpay")
@Slf4j
public class WxPayController {

    @Resource
    private WxPayService wxPayService;

    @Resource
    private OrderMasterDao orderMasterDao;

    @Resource
    private OrderOperationLogDao orderOperationLogDao;

    @PostMapping("/createOrder")
    public R createOrder(@GetUserInfo WxUser wxUser, Long orderId, HttpServletRequest request) {
        Optional<OrderMaster> orderMasterOpt = orderMasterDao.findById(orderId);
        if (!orderMasterOpt.isPresent()) {
            return R.fail("订单不存在");
        }
        OrderMaster orderMaster = orderMasterOpt.get();
        if (orderMaster.getOrderStatus() != 1) {
            return R.fail("订单状态异常,请刷新后重试");
        }
        if (!orderMaster.getUserId().equals(wxUser.getId())) {
            return R.fail("你不是该订单的用户,不能进行该操作");
        }
        String orderNo = orderMaster.getOrderNo();
        int payAmount = orderMaster.getPayAmount().multiply(BigDecimal.valueOf(100)).intValue();// 金额(分)
        String openId = wxUser.getOpenId();
        String startDate = DateUtil.format(new Date(), "yyyyMMddHHmmss");// 订单生成时间
        String endDate = DateUtil.format(DateUtil.offsetMinute(new Date(), 30), "yyyyMMddHHmmss");// 订单失效时间,30分钟后失效
        // 1. 创建统一下单请求对象
        WxPayUnifiedOrderRequest wxRequest = new WxPayUnifiedOrderRequest();
        wxRequest.setOutTradeNo(orderNo); // 本系统订单号
        wxRequest.setTotalFee(payAmount);
        wxRequest.setBody(orderNo); // 商品描述
        wxRequest.setOpenid(openId); // 用户openid
        wxRequest.setTradeType(TradeTypeEnum.JSAPI.toString()); // 交易类型
        // 获取用户ip
        // 获取客户端真实IP（排除内网IP）
        String realIp = IpUtils.getClientRealIp(request);
        // 获取服务器IP
        String serverIp = IpUtils.getServerIp();
        wxRequest.setSpbillCreateIp(IpUtils.isUnknown(realIp) ? serverIp : realIp);
        wxRequest.setTimeStart(startDate);
        wxRequest.setTimeExpire(endDate);
        // 2. 调用统一下单接口 (V2)
        WxPayMpOrderResult orderResult;
        try {
            orderResult = wxPayService.createOrder(wxRequest);
            addOrderLog(wxUser, orderMaster,"wxCreate","订单支付,微信创建订单",orderId,orderResult);
        } catch (WxPayException e) {
            log.error("微信创建订单异常:{}", e.getMessage());
            addOrderLog(wxUser, orderMaster,"wxCreate","订单支付,微信创建订单失败",orderId,e.getMessage());
            return R.fail("微信订单支付异常");
        }

        // 如果你希望使用V3接口下单，可以使用以下方式（需配置V3参数）
        // WxPayUnifiedOrderV3Request v3Request = new WxPayUnifiedOrderV3Request();
        // ... 构建V3请求参数
        // WxPayUnifiedOrderV3Result.JsapiResult orderResult = wxPayService.createOrderV3(TradeTypeEnum.JSAPI, v3Request);

        // 3. 返回支付参数给小程序端

        return R.ok(orderResult);
    }

    @PostMapping("/notify")
    public String payNotify(@RequestBody String xmlData, HttpServletRequest request) throws WxPayException {
        // 1. 解析回调数据并验证签名 (SDK帮我们做了)
        final WxPayOrderNotifyResult notifyResult = wxPayService.parseOrderNotifyResult(xmlData);

        // 2. 获取商户订单号和微信支付订单号
        String outTradeNo = notifyResult.getOutTradeNo();
        String transactionId = notifyResult.getTransactionId();
        log.debug("微信支付回调(/wxpay/notify)商户订单号：{},微信支付订单号：{},微信支付结果：{}", outTradeNo, transactionId, notifyResult.getResultCode());
        // 3. 根据订单号查询本地订单状态，进行幂等性判断（防止重复通知）
        OrderMaster orderMaster = orderMasterDao.findByOrderNo(outTradeNo);
        if (orderMaster == null) {
            return WxPayNotifyResponse.fail("订单不存在");
        }
        if (orderMaster.getOrderStatus() != OrderStatus.ACCEPTED.getKey()) {
            return WxPayNotifyResponse.fail("订单状态不为待支付");
        }
        WxUser wxUser = new WxUser();
        wxUser.setId(orderMaster.getUserId());

        // 4. 判断支付结果
        if ("SUCCESS".equals(notifyResult.getResultCode())) {
            // 支付成功，更新你的订单状态为已支付
            orderMaster.setOrderStatus((byte)OrderStatus.PAID.getKey());
            orderMaster.setPayType((byte)1);
            orderMaster.setPayTime(Instant.now());
            orderMaster.setTransactionId(transactionId);
            orderMasterDao.save(orderMaster);
            addOrderLog(wxUser, orderMaster, "wxNotify", "订单支付,微信回调,支付成功",notifyResult,"支付成功");
            // 成功处理后，返回成功的XML响应给微信
            return WxPayNotifyResponse.success("OK");
        } else {
            // 支付失败，记录日志或进行其他处理
            String notifyJson = JSONUtil.toJsonStr(notifyResult);
            log.error("微信支付失败(/wxpay/notify:error)微信支付失败消息：{}",
                    notifyJson);
            addOrderLog(wxUser, orderMaster, "wxNotify", "订单支付,微信回调,支付失败",notifyResult,"支付失败");
            return WxPayNotifyResponse.fail("FAIL");
        }
    }


    private void addOrderLog(WxUser wxUser, OrderMaster orderMaster,String action, String content,Object request,Object response) {
        // 记录订单日志
        OrderOperationLog orderOperationLog = new OrderOperationLog();
        orderOperationLog.setOrderId(orderMaster.getId());
        orderOperationLog.setOrderNo(orderMaster.getOrderNo());
        orderOperationLog.setOperatorType((byte)1);
        orderOperationLog.setOperatorId(wxUser.getId());
        orderOperationLog.setOperatorName(wxUser.getNickname());
        orderOperationLog.setAction(action);
        orderOperationLog.setContent(content);
        // 判断request和response如果不是基本数据类型,则转换成json字符串
        if (request != null && !request.getClass().isPrimitive()) {
            request=JSON.toJSONString(request);
        }
        if (response != null && !response.getClass().isPrimitive()) {
            response=JSON.toJSONString(response);
        }
        orderOperationLog.setRequestJson(String.valueOf(request));
        orderOperationLog.setResponseJson(String.valueOf(response));
        orderOperationLog.setCreateTime(Instant.now());
        orderOperationLogDao.save(orderOperationLog);
    }

}
